// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: Apache-2.0

package user_msg_api_serv

import (
	"context"

	"gitcode.com/lvupclub/lvup-api/dao"
	"gitcode.com/lvupclub/lvup-api/dao/roadmap_dao"
	"gitcode.com/lvupclub/lvup-api/dao/user_dao"
	"gitcode.com/lvupclub/proto-gen-go.git/src/user_msg_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/user_msg_type_api"
	"google.golang.org/protobuf/types/known/anypb"
)

type UserMsgApiImpl struct {
	user_msg_api.UnimplementedUserMsgApiServer
}

func (apiImpl *UserMsgApiImpl) GetStatus(ctx context.Context, req *user_msg_api.GetStatusRequest) (*user_msg_api.GetStatusResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_msg_api.GetStatusResponse{
			Code:   user_msg_api.GetStatusResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	count, err := user_dao.UserMsgInfoDao.Count(ctx, sessItem.UserId, true, false)
	if err != nil {
		return nil, err
	}
	return &user_msg_api.GetStatusResponse{
		Code:        user_msg_api.GetStatusResponse_CODE_OK,
		UnreadCount: count,
	}, nil
}

func (apiImpl *UserMsgApiImpl) List(ctx context.Context, req *user_msg_api.ListRequest) (*user_msg_api.ListResponse, error) {
	emptyList := []*user_msg_api.UserMsgInfo{}

	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_msg_api.ListResponse{
			Code:    user_msg_api.ListResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			MsgList: emptyList,
		}, nil
	}

	count, err := user_dao.UserMsgInfoDao.Count(ctx, sessItem.UserId, req.FilterByHasRead, req.HasRead)
	if err != nil {
		return nil, err
	}
	msgItemList, err := user_dao.UserMsgInfoDao.List(ctx, sessItem.UserId, req.FilterByHasRead, req.HasRead, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	msgList, err := apiImpl.completeMsgList(ctx, msgItemList)
	if err != nil {
		return nil, err
	}
	return &user_msg_api.ListResponse{
		Code:       user_msg_api.ListResponse_CODE_OK,
		TotalCount: count,
		MsgList:    msgList,
	}, nil
}

func (apiImpl *UserMsgApiImpl) completeMsgList(ctx context.Context, msgItemList []*user_dao.UserMsgInfoDbItem) ([]*user_msg_api.UserMsgInfo, error) {
	msgList := []*user_msg_api.UserMsgInfo{}
	for _, msgItem := range msgItemList {
		msg, err := msgItem.ToUserMsgInfo()
		if err == nil {
			msgList = append(msgList, msg)
		}
	}
	roadmapMemberObjIdList := []string{}
	for _, msg := range msgList {
		recvApplyMsg := &user_msg_type_api.RecvApplyJoinRoadmap{}
		if msg.MsgData.MessageIs(recvApplyMsg) {
			err := msg.MsgData.UnmarshalTo(recvApplyMsg)
			if err != nil {
				return nil, err
			}
			roadmapMemberObjIdList = append(roadmapMemberObjIdList, roadmap_dao.RoadmapMemberDao.GenObjectId(recvApplyMsg.RoadmapId, recvApplyMsg.ApplyUserId))
		}
	}
	roadmapMemberItemList, err := roadmap_dao.RoadmapMemberDao.ListByObjectId(ctx, roadmapMemberObjIdList)
	if err != nil {
		return nil, err
	}
	roadmapMemberObjIdMap := map[string]bool{}
	for _, roadmapMemberItem := range roadmapMemberItemList {
		roadmapMemberObjIdMap[roadmapMemberItem.ObjectId] = true
	}

	for _, msg := range msgList {
		recvApplyMsg := &user_msg_type_api.RecvApplyJoinRoadmap{}
		if msg.MsgData.MessageIs(recvApplyMsg) {
			err := msg.MsgData.UnmarshalTo(recvApplyMsg)
			if err != nil {
				return nil, err
			}
			objId := roadmap_dao.RoadmapMemberDao.GenObjectId(recvApplyMsg.RoadmapId, recvApplyMsg.ApplyUserId)
			recvApplyMsg.IsMember = roadmapMemberObjIdMap[objId]
			msg.MsgData, err = anypb.New(recvApplyMsg)
			if err != nil {
				return nil, err
			}
		}
	}

	return msgList, nil
}

func (apiImpl *UserMsgApiImpl) Get(ctx context.Context, req *user_msg_api.GetRequest) (*user_msg_api.GetResponse, error) {
	emptyInfo := &user_msg_api.UserMsgInfo{
		MsgData: &anypb.Any{},
	}
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_msg_api.GetResponse{
			Code:   user_msg_api.GetResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Msg:    emptyInfo,
		}, nil
	}
	msgItem, err := user_dao.UserMsgInfoDao.Get(ctx, sessItem.UserId, req.MsgId)
	if err != nil {
		return &user_msg_api.GetResponse{
			Code:   user_msg_api.GetResponse_CODE_NO_MSG,
			ErrMsg: "消息不存在",
			Msg:    emptyInfo,
		}, nil
	}
	msgList, err := apiImpl.completeMsgList(ctx, []*user_dao.UserMsgInfoDbItem{msgItem})
	if err != nil {
		return nil, err
	}
	if len(msgList) == 0 {
		return &user_msg_api.GetResponse{
			Code:   user_msg_api.GetResponse_CODE_NO_MSG,
			ErrMsg: "消息不存在",
			Msg:    emptyInfo,
		}, nil
	}
	return &user_msg_api.GetResponse{
		Code: user_msg_api.GetResponse_CODE_OK,
		Msg:  msgList[0],
	}, nil
}

func (apiImpl *UserMsgApiImpl) SetRead(ctx context.Context, req *user_msg_api.SetReadRequest) (*user_msg_api.SetReadResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_msg_api.SetReadResponse{
			Code:   user_msg_api.SetReadResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	exist, err := user_dao.UserMsgInfoDao.Exist(ctx, sessItem.UserId, req.MsgId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_msg_api.SetReadResponse{
			Code:   user_msg_api.SetReadResponse_CODE_NO_MSG,
			ErrMsg: "消息不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx context.Context) (interface{}, error) {
		err = user_dao.UserMsgInfoDao.SetHasRead(sessCtx, sessItem.UserId, req.MsgId)
		if err != nil {
			return nil, err
		}
		return &user_msg_api.SetReadResponse{
			Code: user_msg_api.SetReadResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_msg_api.SetReadResponse), nil
}

func (apiImpl *UserMsgApiImpl) Remove(ctx context.Context, req *user_msg_api.RemoveRequest) (*user_msg_api.RemoveResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_msg_api.RemoveResponse{
			Code:   user_msg_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	msgItem, err := user_dao.UserMsgInfoDao.Get(ctx, sessItem.UserId, req.MsgId)
	if err != nil {
		return &user_msg_api.RemoveResponse{
			Code: user_msg_api.RemoveResponse_CODE_OK,
		}, nil
	}
	msg, err := msgItem.ToUserMsgInfo()
	if err != nil {
		return nil, err
	}
	recvApplyJoinMsg := &user_msg_type_api.RecvApplyJoinRoadmap{}
	if msg.MsgData.MessageIs(recvApplyJoinMsg) {
		err = msg.MsgData.UnmarshalTo(recvApplyJoinMsg)
		if err != nil {
			return nil, err
		}
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx context.Context) (interface{}, error) {
		if recvApplyJoinMsg.RoadmapId != "" && recvApplyJoinMsg.ApplyUserId != "" {
			err = roadmap_dao.ApplyInfoDao.Remove(sessCtx, recvApplyJoinMsg.RoadmapId, recvApplyJoinMsg.ApplyUserId)
			if err != nil {
				return nil, err
			}
		}
		err = user_dao.UserMsgInfoDao.Remove(sessCtx, sessItem.UserId, req.MsgId)
		if err != nil {
			return nil, err
		}
		return &user_msg_api.RemoveResponse{
			Code: user_msg_api.RemoveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_msg_api.RemoveResponse), nil
}
